home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d945.lha / Reminder / src / src.lha / Events.c < prev    next >
C/C++ Source or Header  |  1993-04-19  |  12KB  |  462 lines

  1. /* Event handling routines for Reminder */
  2.  
  3. /* $Id: Events.c,v 1.14 1993/04/18 21:54:08 Matti_Rintala Exp $ */
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <errno.h>
  8. #include <time.h>
  9.  
  10. #include <exec/types.h>
  11. #include <exec/lists.h>
  12.  
  13. #include <exec/exec.h>
  14. #include <libraries/reqtools.h>
  15.  
  16. #ifdef __SASC
  17. #include <proto/exec.h>
  18. #include <proto/reqtools.h>
  19. #endif
  20.  
  21. #ifdef _DCC
  22. #include <clib/exec_protos.h>
  23. #include <clib/reqtools_protos.h>
  24. #endif
  25.  
  26. #include "Globals.h"
  27. #include "CalcDate.h"
  28. #include "Events.h"
  29.  
  30. static int checkdate(void);
  31. static void makeentry(char *entry, short day, short month, short year,
  32.               short wday, const char *text);
  33.  
  34. static int AddEventlist(struct EventNode *newevent);
  35.  
  36. /* Eventlist holds the event database, initially empty */
  37. static struct List Eventlist = {
  38.   (struct Node *)&Eventlist.lh_Tail,
  39.   NULL,
  40.   (struct Node *)&Eventlist.lh_Head
  41.   };
  42.  
  43. static time_t today;        /* Date of current day (initialized in LoadEvents) */
  44.  
  45. static void DeleteEventlist(void);
  46.  
  47. /* InitEvents initializes the events database */
  48. struct List *InitEvents(void) {
  49.  
  50.   /* Only ensure that Eventlist is deleted on exit */
  51.   atexit(DeleteEventlist);
  52.  
  53.   /* Return pointer to Eventlist */
  54.   return &Eventlist;
  55. }
  56.  
  57. static void DeleteEventlist(void) {
  58.  
  59.   struct EventNode *node;
  60.  
  61.   while ((node = (struct EventNode *)RemTail(&Eventlist)) != NULL)
  62.     free(node);
  63.  
  64.   eventno = 0;            /* There are no events now */
  65.  
  66. }
  67.  
  68. /* NewEvent makes a new, clear event */
  69. void NewEvent(void) {
  70.  
  71.   /* Ask for confirmation if event in gadgets has been edited */
  72.   if (edited) {
  73.     if (!rtEZRequestTags("You have edited\nthe current event.\nAbandon changes?",
  74.              "_Yes|Oh, _no!", NULL, NULL, RT_LockWindow, (Tag)TRUE,
  75.              RT_Underscore, (Tag)'_', RTEZ_DefaultResponse, (Tag)0,
  76.              TAG_END)) {
  77.       /* If user does not want to abandon changes */
  78.       return;
  79.     }
  80.   }
  81.  
  82.   /* Initialize all variables */
  83.   day = month = year = wday = before = after = 0;
  84.   autodelete = FALSE; grouped = FALSE;
  85.   swdaytxt = NULL;
  86.   mode = AREXXNMODE;
  87.   text[0] = arexxport[0] = arexxcom[0] = '\0';
  88.   event = ~0;            /* No event selected */
  89.  
  90.   edited = FALSE;        /* Nothing edited now */
  91. }
  92.  
  93. /* AddEvent adds a new event to list */
  94. struct List *AddEvent(void) {
  95.  
  96.   struct EventNode *newevent;
  97.  
  98.   /* Check that the date is correct */
  99.   if (!checkdate()) {
  100.     /* If not, tell the user that */
  101.     rtEZRequestTags("Cannot add event,\ninvalid date.", "OK", NULL, NULL,
  102.             RT_LockWindow, (Tag)TRUE, TAG_END);
  103.     /* Return with unchanged list */
  104.     return &Eventlist;
  105.   }
  106.  
  107.   /* Make a new list node */
  108.   if ((newevent = malloc(sizeof(struct EventNode))) == NULL) {
  109.     rtEZRequestTags("Cannot get memory\nfor new event!", "OK", NULL, NULL,
  110.             RT_LockWindow, (Tag)TRUE, TAG_END);
  111.     return &Eventlist;
  112.   }
  113.  
  114.   /* Generate entry text */
  115.   makeentry(newevent->entry, day, month, year, wday, text);
  116.   newevent->node.ln_Name = newevent->entry;
  117.  
  118.   /* Set Acknowledgement date to 1-Jan-1990 */
  119.   newevent->aday = 1; newevent->amonth = 1; newevent->ayear = 1990;
  120.  
  121.   /* Set other fields from globals */
  122.   newevent->day = day; newevent->month = month; newevent->year = year;
  123.   newevent->wday = wday;
  124.   newevent->before = before; newevent->after = after;
  125.   newevent->autodelete = autodelete;
  126.   strncpy(newevent->text, text, TEXTLEN);
  127.   strncpy(newevent->arexxcom, arexxcom, AREXXCOMLEN);
  128.   strncpy(newevent->arexxport, arexxport, AREXXPORTLEN);
  129.   newevent->mode = mode | (grouped ? GROUPEDMASK : 0);
  130.  
  131.   /* Add new entry */
  132.   event = AddEventlist(newevent);
  133.  
  134.   changed = 1;        /* Database has changed */
  135.   eventno++;            /* One more event now exists */
  136.  
  137.   edited = FALSE;        /* Nothing has been edited now */
  138.  
  139.   /* Return pointer to list */
  140.   return &Eventlist;
  141. }
  142.  
  143. /* Getevent gets data from selected event */
  144. int GetEvent(void) {
  145.  
  146.   struct EventNode *node;
  147.   int i;
  148.  
  149.   /* Ask for confirmation if event in gadgets has been edited */
  150.   if (edited) {
  151.     if (!rtEZRequestTags("You have edited\nthe current event.\nAbandon changes?",
  152.              "_Yes|Oh, _no!", NULL, NULL, RT_LockWindow, (Tag)TRUE,
  153.              RT_Underscore, (Tag)'_', RTEZ_DefaultResponse, (Tag)0,
  154.              TAG_END)) {
  155.       /* If user does not want to abandon changes */
  156.       return FALSE;
  157.     }
  158.   }
  159.  
  160.   /* First find the appropriate node */
  161.   node = (struct EventNode *)Eventlist.lh_Head;
  162.   for (i = 0 ; i < event; i++)
  163.     node = (struct EventNode *)node->node.ln_Succ;
  164.  
  165.   /* Then get the appropriate data */
  166.   wday = node->wday; day = node->day; month = node->month; year = node->year;
  167.   before = node->before; after = node->after;
  168.   autodelete = node->autodelete;
  169.   strncpy(text, node->text, TEXTLEN);
  170.   strncpy(arexxcom, node->arexxcom, AREXXCOMLEN);
  171.   strncpy(arexxport, node->arexxport, AREXXPORTLEN);
  172.   mode = node->mode & ~GROUPEDMASK;
  173.   grouped = ((node->mode & GROUPEDMASK) != 0);
  174.  
  175.   edited = FALSE;        /* Nothing has been edited */
  176.  
  177.   return TRUE;
  178. }
  179.  
  180. /* UpdateEvent updates an existing event */
  181. struct List *UpdateEvent(void) {
  182.  
  183.   struct EventNode *node;
  184.   int i;
  185.  
  186.   /* First find the appropriate node */
  187.   node = (struct EventNode *)Eventlist.lh_Head;
  188.   for (i = 0 ; i < event; i++)
  189.     node = (struct EventNode *)node->node.ln_Succ;
  190.  
  191.   /* Remove the node from EventList */
  192.   Remove((struct Node *)node);
  193.   eventno--;
  194.  
  195.   /* Generate entry text */
  196.   makeentry(node->entry, day, month, year, wday, text);
  197.   node->node.ln_Name = node->entry;
  198.  
  199.   /* Set Acknowledgement date to 1-Jan-1990 */
  200.   node->aday = 1; node->amonth = 1; node->ayear = 1990;
  201.  
  202.   /* Set other fields from globals */
  203.   node->day = day; node->month = month; node->year = year;
  204.   node->wday = wday;
  205.   node->before = before; node->after = after;
  206.   node->autodelete = autodelete;
  207.   strncpy(node->text, text, TEXTLEN);
  208.   strncpy(node->arexxcom, arexxcom, AREXXCOMLEN);
  209.   strncpy(node->arexxport, arexxport, AREXXPORTLEN);
  210.   node->mode = mode | (grouped ? GROUPEDMASK : 0);
  211.  
  212.   /* Add event back to list */
  213.   event = AddEventlist(node);
  214.   eventno++;
  215.  
  216.   changed = 1;        /* Database has changed */
  217.  
  218.   edited = FALSE;        /* Nothing has been edited */
  219.  
  220.   return &Eventlist;
  221. }
  222.  
  223. /* RemoveEvent removes an existing event */
  224. struct List *RemoveEvent(void) {
  225.  
  226.   struct EventNode *node;
  227.   int i;
  228.  
  229.   /* First find the appropriate node */
  230.   node = (struct EventNode *)Eventlist.lh_Head;
  231.   for (i = 0 ; i < event; i++)
  232.     node = (struct EventNode *)node->node.ln_Succ;
  233.  
  234.   /* Remove the node */
  235.   Remove((struct Node *)node);
  236.  
  237.   /* Free the memory */
  238.   free(node);
  239.  
  240.   changed = 1;            /* Database has changed */
  241.   eventno--;            /* Now there are one less events */
  242.  
  243.   return &Eventlist;
  244. }
  245.  
  246. /* LoadEvents loads the event database from file. It returns TRUE if it fails. */
  247. int LoadEvents(const char *filename) {
  248.  
  249.   FILE *infile;
  250.   struct EventNode *node;
  251.  
  252.   /* Get todays date */
  253.   gettoday(&today);
  254.  
  255.   /* Try to open the file */
  256.   if ((infile = fopen(filename, "rb")) == NULL) 
  257.     return TRUE;
  258.  
  259.   /* Skip the timestamp */
  260.   fseek(infile, sizeof(time_t), SEEK_SET);
  261.  
  262.   /* Read events from file */
  263.   while (TRUE) {
  264.     /* Get memory for event */
  265.     if ((node = malloc(sizeof(struct EventNode))) == NULL) {
  266.       rtEZRequestTags("Insufficient memory!", "OK", NULL, NULL,
  267.               RT_LockWindow, (Tag)TRUE, TAG_END);
  268.       break;
  269.     }
  270.  
  271.     /* Read event part of it from file */
  272.     while (TRUE) {
  273.       fread(SAVEADDR(node), 1, SAVELEN(node), infile);
  274.       /* If end-of-file occurred, stop looping */
  275.       if (feof(infile))
  276.     break;
  277.       /* Stop looping also, if event is not deleted */
  278.       if (node->mode != DELETEDMODE)
  279.     break;
  280.       else
  281.     changed = 2;        /* Deleted entrys should be swept away */
  282.     }
  283.     /* If end-of-file occurred, stop looping */
  284.     if (feof(infile))
  285.       break;
  286.  
  287.     /* Check mode (for database files generated with Reminder V1.00) */
  288.     if ((node->mode & ~GROUPEDMASK) != AREXXCMODE &&
  289.     (node->mode & ~GROUPEDMASK) != AREXXSMODE &&
  290.     (node->mode & ~GROUPEDMASK) != AREXXNMODE) {
  291.       /* Invalid mode, use No ARexx, no grouping and empty Port and Com fields */
  292.       node->mode = AREXXNMODE;
  293.       node->arexxcom[0] = node->arexxport[0] = '\0';
  294.     }
  295.  
  296.     /* Calculate entry text */
  297.     makeentry(node->entry, node->day, node->month, node->year, node->wday,
  298.           node->text);
  299.  
  300.     /* Set name of event and add it to Eventlist */
  301.     node->node.ln_Name = node->entry;
  302.     AddEventlist(node);
  303.     eventno++;            /* One more event */
  304.   }
  305.  
  306.   /* Free the extra node left (freeing NULL is allowed) */
  307.   free(node);
  308.  
  309.   fclose(infile);
  310.  
  311.   return FALSE;
  312. }
  313.  
  314. /* SaveEvents saves event database to file. It returns TRUE if it fails. */
  315. int SaveEvents(const char *filename) {
  316.  
  317.   FILE *outfile;
  318.   struct EventNode *node;
  319.   BOOL success = TRUE;
  320.   struct tm tm_stamp = {0, 0, 0, 1, 0, 90, 0, 0, 0};
  321.   time_t stamp;
  322.   
  323.   /* First try to open the file */
  324.   if ((outfile = fopen(filename, "wb")) == NULL)
  325.     return 1;
  326.  
  327.   /* Write timestamp for 1.1.1990 */
  328.   stamp = mktime(&tm_stamp);
  329.   if (fwrite(&stamp, 1, sizeof(time_t), outfile) != sizeof(time_t)) {
  330.     success = FALSE;
  331.   }
  332.   else {
  333.     node = (struct EventNode *)Eventlist.lh_Head;
  334.     for (; node->node.ln_Succ != NULL;
  335.      node = (struct EventNode *)node->node.ln_Succ) {
  336.       /* Write the node information to file */
  337.       if (fwrite(SAVEADDR(node), 1, SAVELEN(node), outfile) != SAVELEN(node)) {
  338.     /* If failed, abort */
  339.     success = FALSE;
  340.     break;
  341.       }
  342.     }
  343.   }
  344.  
  345.   /* Close the file and exit */
  346.   fclose(outfile);
  347.  
  348.   return !success;
  349. }
  350.  
  351.   
  352.  
  353. static short monthlist[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  354.  
  355. /* checkdate checks that the date is valid */
  356. static int checkdate(void) {
  357.  
  358.   short testyear, testmonth;
  359.   /* Check month */
  360.   if (month > 12)
  361.     return 0;
  362.  
  363.   /* If day is ANY, date is ok */
  364.   if (day == 0)
  365.     return 1;
  366.  
  367.   /* Get appropiate values for test variables */
  368.   if (year == 0) testyear = 1996; /* Leap year */
  369.   else testyear = year;
  370.  
  371.   if (month == 0) testmonth = 1; /* Month with 31 days */
  372.   else testmonth = month;
  373.     
  374.   /* Check day */
  375.   if (day > (monthlist[testmonth-1] + ((testmonth == 2 && testyear%4 == 0) ?
  376.                      ((testyear%400 == 0) ? 0 : 1) :
  377.                      0)))
  378.     return 0;
  379.  
  380.   return 1;
  381. }
  382.  
  383. /* makeentry makes an appropriate entry line for Eventlist gadget */
  384. static void makeentry(char *entrystart, short day, short month, short year,
  385.               short wday, const char *text) {
  386.  
  387.   char *entry = entrystart;
  388.  
  389.   /* Start with day of the week */
  390.   /* If we have a non-repeating date with ANY weekday, show the weekday + colon */
  391.   if (day != 0 && month != 0 && year != 0 && wday == 0) {
  392.     strncpy(entry, wdayabbrv+4*weekday(day, month, year), 3);
  393.     entry += 3;
  394.     *entry++ = ':';
  395.   }
  396.   else {
  397.     strncpy(entry, wdayabbrv+4*wday, 3);
  398.     entry += 3;            /* Skip the day */
  399.     *entry++ = ' ';
  400.   }
  401.  
  402.   /* If day is ANY, use **, otherwise the day number */
  403.   if (day == 0) {
  404.     *entry++ = '*';
  405.     *entry++ = '*';
  406.   }
  407.   else {
  408.     sprintf(entry, "%02d", day);
  409.     entry += 2;            /* Skip over the number */
  410.   }
  411.  
  412.   *entry++ = '-';
  413.   /* Then month name */
  414.   strncpy(entry, monthabbrv+4*month, 3);
  415.   entry += 3;            /* Skip over month */
  416.   *entry++ = '-';
  417.  
  418.   /* Then year */
  419.   if (year == 0) {
  420.     *entry++ = '*';
  421.     *entry++ = '*';
  422.     *entry++ = '*';
  423.     *entry++ = '*';
  424.   }
  425.   else {
  426.     sprintf(entry, "%4d", year);
  427.     entry += 4;            /* Skip over year */
  428.   }
  429.  
  430.   *entry++ = ' ';
  431.  
  432.   /* Then copy rest with text */
  433.   strncpy(entry, text, ENTRYLEN-(entry-entrystart));
  434. }
  435.  
  436. /* AddEventlist finds the correct place for event and adds it to list.
  437.    It returns the place of the event in the list */
  438. static int AddEventlist(struct EventNode *newevent) {
  439.  
  440.   int i;
  441.   struct EventNode *node;
  442.  
  443.   /* Calculate next occurrence of event */
  444.   makedate(&newevent->next_date, &today, newevent->day, newevent->month,
  445.        newevent->year, newevent->wday);
  446.  
  447.   /* Find place for event, starting form the head of list */
  448.   node = (struct EventNode *)Eventlist.lh_Head;
  449.   for (i = 0; i < eventno; i++, node = (struct EventNode *)node->node.ln_Succ) {
  450.     /* If event is earlier than this, add new event before it */
  451.     if (newevent->next_date < node->next_date) {
  452.       Insert(&Eventlist, (struct Node *)newevent, node->node.ln_Pred);
  453.       return i;            /* Return place of event */
  454.     }
  455.   }
  456.  
  457.   /* If we got this far, event must be added to the end of the list */
  458.   AddTail(&Eventlist, (struct Node *)newevent);
  459.   return eventno;        /* Event is the last one */
  460. }
  461.  
  462.